package com.zxy.ziems.server.device.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zxy.btp.common.util.JsonUtils;
import com.zxy.ziems.common.mqtt.pojo.MqttMessagePayload;
import com.zxy.ziems.common.mqtt.template.MqttClientTemplate;
import com.zxy.ziems.common.pojo.collector.Channel;
import com.zxy.ziems.common.pojo.collector.ChannelDevice;
import com.zxy.ziems.common.pojo.collector.Config;
import com.zxy.ziems.common.pojo.collector.Unit;
import com.zxy.ziems.server.device.convertor.DeviceConvertor;
import com.zxy.ziems.server.device.mapper.CollectorMapper;
import com.zxy.ziems.server.device.pojo.dto.CollectorDTO;
import com.zxy.ziems.server.device.pojo.entity.ChannelEntity;
import com.zxy.ziems.server.device.pojo.entity.CollectorEntity;
import com.zxy.ziems.server.device.pojo.entity.DataUnitEntity;
import com.zxy.ziems.server.device.pojo.entity.ProtocolEntity;
import com.zxy.ziems.server.device.pojo.vo.CollectorVO;
import com.zxy.ziems.server.device.service.*;
import com.zxy.ziems.server.mybatis.core.service.ServiceImplX;
import com.zxy.ziems.server.utils.AssertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 10348359
 * @create 2024-03-25 13:12
 */
@Service
public class CollectorServiceImpl extends ServiceImplX<CollectorMapper, CollectorEntity> implements CollectorService {
    @Override
    public void upload(CollectorDTO dto) {
        CollectorEntity entity = getByCode(dto.getCode());
        if (Objects.isNull(entity)) {
            entity = DeviceConvertor.INSTANCE.collectorDTOConvert2DO(dto);
            entity.setOnlineStatus(1);
            save(entity);
        } else {
            String id = entity.getId();
            entity = DeviceConvertor.INSTANCE.collectorDTOConvert2DO(dto);
            entity.setOnlineStatus(1);
            entity.setId(id);
            updateById(entity);
        }
    }

    @Override
    public void update(CollectorDTO dto) {
        AssertUtil.nonNull(getById(dto.getId()), "采集器不存在");
        CollectorEntity old = getByCode(dto.getCode());
        AssertUtil.isTrue(Objects.isNull(old) || old.getId().equals(dto.getId()), "编码重复");
        CollectorEntity entity = DeviceConvertor.INSTANCE.collectorDTOConvert2DO(dto);
        updateById(entity);
    }

    @Override
    public void deleteById(String id) {
        if (StrUtil.isBlank(id)) {
            return;
        }
        removeById(id);
    }

    @Override
    public CollectorEntity getByCode(String code) {
        return getOne(CollectorEntity::getCode, code);
    }


    @Override
    public CollectorEntity getById(String id) {
        return super.getById(id);
    }

    @Override
    public List<CollectorEntity> listByIdList(Collection<String> idList) {
        return super.listByIds(idList);
    }

    @Override
    public List<CollectorVO> viewList() {
        List<CollectorEntity> list = list();
        return DeviceConvertor.INSTANCE.collectorDOListConvert2VOList(list);
    }

    @Override
    public void downloadConfigurationById(String id) {
        CollectorEntity entity = getById(id);
        AssertUtil.nonNull(entity, "采集器不存在");

        String collectorCode = entity.getCode();

        List<ChannelEntity> channelEntities = channelService.listByCollectorId(id);
        Set<String> protocolIdSet = channelEntities.stream().map(ChannelEntity::getProtocolId).collect(Collectors.toSet());

        Map<String, ProtocolEntity> protocolMap = protocolService.listByIdList(protocolIdSet)
                .stream()
                .collect(Collectors.toMap(ProtocolEntity::getId, a->a));
        Set<String> unitIdSet = new HashSet<>();
        List<Channel> channels = channelEntities.stream().map((a) -> {
            ProtocolEntity protocolEntity = protocolMap.get(a.getProtocolId());
            Channel channel = new Channel();
            channel.setId(a.getId());
            channel.setIp(a.getIp());
            channel.setPort(a.getPort());
            channel.setName(a.getName());
            channel.setCollectorId(id);
            channel.setProtocol(Objects.nonNull(protocolEntity)?protocolEntity.getCode(): null);
            channel.setDeviceTypeCode(a.getDeviceTypeCode());
            List<ChannelDevice> devices = channelDeviceService.deviceListByChannelId(a.getId());
            devices.forEach((a0)-> {
                a0.getPropertyList().forEach((a1)-> {
                    if (StrUtil.isNotBlank(a1.getUnitId())) {
                        unitIdSet.add(a1.getUnitId());
                    }
                    if (StrUtil.isNotBlank(a1.getDataUnitId())) {
                        unitIdSet.add(a1.getDataUnitId());
                    }
                });
            });
            channel.setDevices(devices);
            return channel;
        }).toList();

        List<DataUnitEntity> dataUnitEntities = dataUnitService.listByIdList(unitIdSet);

        List<Unit> units = dataUnitEntities.stream().map((a) -> {
            Unit u = new Unit();
            u.setId(a.getId());
            u.setMultiple(a.getMultiple());
            u.setDivisor(a.getDivisor());
            return u;
        }).toList();

        Config config = new Config();
        config.setChannels(channels);
        config.setUnits(units);

        entity = new CollectorEntity();
        entity.setId(id);
        entity.setConfig(JsonUtils.toJSONString(config));
        updateById(entity);

        if (Objects.nonNull(clientTemplate)) {
            String topic = "server/updateCollectorConfig/" + collectorCode;
            clientTemplate.publishPayload(topic, config);
        }
    }

    @Override
    public Config getConfigByCollectorCode(String code) {
        CollectorEntity entity = getByCode(code);
        AssertUtil.nonNull(entity, "采集器不存在");
        AssertUtil.isTrue(StrUtil.isNotBlank(entity.getConfig()), "配置不存在");
        return JsonUtils.parseObject(entity.getConfig(), Config.class) ;
    }

    private ChannelService channelService;

    @Lazy
    @Autowired
    public void setChannelService(ChannelService channelService) {
        this.channelService = channelService;
    }

    private ChannelDeviceService channelDeviceService;

    @Lazy
    @Autowired
    public void setChannelDeviceService(ChannelDeviceService channelDeviceService) {
        this.channelDeviceService = channelDeviceService;
    }

    private DataUnitService dataUnitService;

    @Autowired
    public void setDataUnitService(DataUnitService dataUnitService) {
        this.dataUnitService = dataUnitService;
    }

    private ProtocolService protocolService;

    @Autowired
    public void setProtocolService(ProtocolService protocolService) {
        this.protocolService = protocolService;
    }


    private MqttClientTemplate clientTemplate;

    @Autowired(required = false)
    public void setClientTemplate(MqttClientTemplate mqttClientTemplate) {
        this.clientTemplate = mqttClientTemplate;
    }
}
